import { Globals, Dir } from "./Global";
import AuidoMgr from "./AudioMgr"
import Game from "./Game"
import AudioMgr from "./AudioMgr";
import PlayerTank from "./PlayerTank";
import BaseTank from "./BaseTank";
import Bullet from "./Bullet";
import BlockWall from "./BlockWall"
import EnemyTank from "./EnemyTank";
import UpdateInfomations from "./UpdateInfomations";
import Prop from "./Prop"
import { log_debug } from "./Utils";
import BlockStone from "./BlockStone";

const {ccclass, property} = cc._decorator;

@ccclass
export default class MapLayer extends cc.Component {
    // 节点信息
    @property(cc.Node)
    playerNode: cc.Node = null;

    @property(cc.Node)
    enemiesNode: cc.Node = null;

    @property(cc.Node)
    blocksNode: cc.Node = null;

    @property(cc.Node)
    enemyBulletsNode: cc.Node = null;

    @property(cc.Node)
    playerBulletsNode: cc.Node = null;

    @property(cc.Node)
    propNode: cc.Node = null;

    // 预制信息
    @property(cc.Prefab)
    blockWallPrefab: cc.Prefab = null;

    @property(cc.Prefab)
    blockStonePrefab: cc.Prefab = null;

    @property(cc.Prefab)
    blockIcePrefab: cc.Prefab = null;

    @property(cc.Prefab)
    blockForestPrefab: cc.Prefab = null;

    @property(cc.Prefab)
    blockRiverPrefab: cc.Prefab = null;

    @property(cc.Prefab)
    enemyPrefab: cc.Prefab = null;

    @property(cc.Prefab)
    playerPrefab: cc.Prefab = null;

    @property(cc.Prefab)
    bulletPrefab: cc.Prefab = null;

    @property(cc.Prefab)
    propPrefab: cc.Prefab = null;

    // 其他变量
    _remainEnemiesCount: number;
    _propEnemiesCount: number;
    _canCreatePropTank: boolean;
    _game: Game;
    _audioMgr: AuidoMgr;
    _bulletPool: cc.NodePool;
    _enemiesPool: cc.NodePool;
    _propPool: cc.NodePool;
    isPropStopping: boolean;

    onLoad() {
        this._game = cc.find("/Game").getComponent(Game);
        this._audioMgr = cc.find("/Game/AudioMgr").getComponent(AudioMgr);
        this._bulletPool = new cc.NodePool();
        this._enemiesPool = new cc.NodePool();
        this._propPool = new cc.NodePool();

        // 玩家坦克出生
        this.spawnPlayer();
    }

    init() {
        this._remainEnemiesCount = Globals.ENEMIES_COUNT;
        this._propEnemiesCount = 0;
        this._canCreatePropTank = false;
        this.isPropStopping = false;

        this._cleanChildNode();

        // 加载地图
        this._loadMap();
        	
        // 生成敌人
        this.spawnNewEnemy();

        // 初始化玩家
        for (const player of this.playerNode.children) {
            player.getComponent(PlayerTank).reset();
        }

        // 每隔3秒生成一个敌人
        this.schedule(this.spawnNewEnemy, 3);

        // 检查游戏是否胜利
        this.schedule(() => {
            if (this.enemiesNode.childrenCount <= 0 && this._remainEnemiesCount <= 0) {
                this.unscheduleAllCallbacks();
                this.scheduleOnce(() => {
                    // 2s后切到下一关
                    this._toNextStage();
                }, 2);
            }
        }, 0.1);
    }

    randomMaxPropTankCount() {
        let instance_level = this._game.level;
        // 前10关最多出现1次道具坦克
        if (instance_level < 10) {
            return 1;
        } else if (instance_level < 20) {
            return 2;
        }
        return 3;
    }

    spawnPlayer() {
        let player = cc.instantiate(this.playerPrefab);
        player.parent = this.playerNode;
        player.getComponent(PlayerTank).init();
    }

    spawnNewEnemy() {
        if (this.enemiesNode.childrenCount >= 6) {
            return;
        }

        if (this._remainEnemiesCount <= 0) {
            return;
        } else if (this._remainEnemiesCount < Globals.PROP_APPEAR_REMAIN_COUNT) {
            this._canCreatePropTank = true;
        }

        if (this._remainEnemiesCount == Globals.ENEMIES_COUNT) {
            this.createEnemy(Globals.ENEMY1);
            this.createEnemy(Globals.ENEMY2);
            this.createEnemy(Globals.ENEMY3);
        } else if (this._remainEnemiesCount > 0) {
            let choice = Math.floor(Math.random() * 3);
            let pos: cc.Vec2;
            if (choice == 0) {
                pos = Globals.ENEMY1;
            } else if (choice == 1) {
                pos = Globals.ENEMY2;
            } else {
                pos = Globals.ENEMY3;
            }
            if (this._canSpawnTank(pos)) {
                this.createEnemy(pos);
            }
        } else {
            this.unschedule(this.spawnNewEnemy);
        }
    }

    createEnemy(pos: cc.Vec2) {
        let enemy: cc.Node;

        if (this._enemiesPool.size() > 0) {
            enemy = this._enemiesPool.get();
        } else {
            enemy = cc.instantiate(this.enemyPrefab);
        }

        // 随机看是不是道具坦克
        let isPropTank = false;
        if (this._canCreatePropTank && this._propEnemiesCount < this.randomMaxPropTankCount()) {
            let choice = Math.floor(Math.random() * 100);
            if (choice < Globals.PROP_APPEAR_WEIGHT) {
                isPropTank = true;
                this._propEnemiesCount += 1;
            }
            if (this._propEnemiesCount >= this.randomMaxPropTankCount()) {
                this._canCreatePropTank = false;
            }
        }

        enemy.parent = this.enemiesNode;
        enemy.getComponent(EnemyTank).init(new cc.Vec3(pos.x, pos.y), isPropTank);

        cc.find("/Canvas/GameLayer/Infomations").getComponent(UpdateInfomations).deleteOneIcon();
        this._remainEnemiesCount -= 1;
    }

    destoryEnemy(enemy: cc.Node) {
        enemy.removeFromParent();
        this._enemiesPool.put(enemy);
    }

    createBullet(dir: Dir, pos: cc.Vec3, step: number, tank: BaseTank) {
        if (tank.bulletCount <= 0) {
            return false;
        }

        let bullet: cc.Node;

        if (this._bulletPool.size() > 0) {
            bullet = this._bulletPool.get();
        } else {
            bullet = cc.instantiate(this.bulletPrefab);
        }

        if (tank.isEnemy) {
            bullet.parent = this.enemyBulletsNode;
        } else {
            bullet.parent = this.playerBulletsNode;
        }

        bullet.getComponent(Bullet).init(dir, pos, step, tank);

        return true;
    }

    destoryBullet(bullet: cc.Node) {
        bullet.removeFromParent();
        this._bulletPool.put(bullet);
    }

    _canSpawnTank(pos: cc.Vec2) {
        let box = new cc.Rect(
            pos.x - Globals.TANK_SIZE / 2,
            pos.y - Globals.TANK_SIZE / 2,
            Globals.TANK_SIZE,
            Globals.TANK_SIZE
        );

        for (const player of this.playerNode.children) {
            if (box.intersects(player.getBoundingBox())) {
                return false;
            }            
        }

        let enemies = this.enemiesNode.children;
        for (const enemy of enemies) {
            if (box.intersects(enemy.getBoundingBox())) {
                return false;
            }
        }

        return true;
    }

    spawnProp() {
        let props = this.propNode.children;
        if (props.length > 0) {
            this.destroyProp(props[0]);
        }
        let prop: cc.Node;
        if (this._propPool.size() > 0) {
            prop = this._propPool.get();
        } else {
            prop = cc.instantiate(this.propPrefab);
        }
        prop.parent = this.propNode;
        prop.getComponent(Prop).init();
    }

    takeProp() {
        let props = this.propNode.children;
        if (props.length <= 0) {
            return;
        }

        let prop = props[0];
        prop.getComponent(Prop).takeEffect();
    }

    destroyProp(prop: cc.Node) {
        prop.removeFromParent();
        this._propPool.put(prop);
    }

    propStopEnemyTank() {
        this.isPropStopping = true;
        this.scheduleOnce(()=>{
            this.isPropStopping = false; 
        }, Globals.ENEMY_STOP_SECS);
    }

    propClearEnemyTank() {
        let enemies = this.enemiesNode.children;
        for (let i=0; i<enemies.length; i++) {
            let enemy = enemies[i];
            enemy.getComponent(EnemyTank).onEnemyDestroyed(true);
        }
    }

    propPlayerInvicible() {
        for (const player of this.playerNode.children) {
            player.getComponent(PlayerTank).onInvincible();
        }
    }

    propPlayerAddLevel() {
        for (const player of this.playerNode.children) {
            player.getComponent(PlayerTank).updateLevel();
        }
    }

    propPlayerAddLife() {
        for (const player of this.playerNode.children) {
            let old_blood = player.getComponent(PlayerTank).blood
            let new_blood = old_blood + 1
            player.getComponent(PlayerTank).blood = new_blood;
            cc.find("/Canvas/GameLayer/Infomations").getComponent(UpdateInfomations).updatePlayerBlood(new_blood-1);
        }
    }

    propReinoforce() {
        let reinforcePosBlocks = [
            [88, 0], [112, 0],
            [88, 8], [112, 8],
            [88, 16], [96, 16], [104, 16], [112, 16],
        ];
        
        let blockWalls = [];
        let blockStones = [];
        for (let i=0; i!=reinforcePosBlocks.length; ++i) {
            let pos = cc.v2(reinforcePosBlocks[i][0], reinforcePosBlocks[i][1]);

            let block: cc.Node;

            // 先补充被打掉的blockwall
            let allBlocks = this.blocksNode.children;
            for (let i=0; i!= allBlocks.length; ++i) {
                let tmpBlock = allBlocks[i];
                if (tmpBlock.name == "block_wall" && tmpBlock.getPosition().equals(pos)) {
                    block = tmpBlock;
                    break;
                }
            }

            if (!block) {
                block = cc.instantiate(this.blockWallPrefab);
                block.getComponent(BlockWall).in_reinforce = true;
                block.name = "block_wall";
                block.getComponent(BlockWall).init();
                block.setAnchorPoint(0, 0);
                block.setPosition(pos);
                block.parent = this.blocksNode;
            } else {
                block.getComponent(BlockWall).in_reinforce = true;
            }
            blockWalls.push(block);
            
            // 再用blockstone覆盖
            block = cc.instantiate(this.blockStonePrefab);
            block.name = "block_stone";
            block.getComponent(BlockStone).init();
            block.setAnchorPoint(0, 0);
            block.setPosition(pos);
            block.parent = this.blocksNode;
            blockStones.push(block);
        }

        // 加固20s+3s
        this.scheduleOnce(() => {
            for (let i=0; i!=blockStones.length; ++i) {
                blockStones[i].runAction(cc.blink(3, 8));
            }
            this.scheduleOnce(() => {
                for (let i=0; i!=blockStones.length; ++i) {
                    blockStones[i].destroyAllChildren();
                    blockStones[i].destroy();
                }
                blockStones = null;
                for (let i=0; i!=blockWalls.length;++i) {
                    blockWalls[i].getComponent(BlockWall).in_reinforce = false;
                }
                blockWalls = null;
            }, 3);
        }, Globals.REINFORCE_TIME);
    }

    _cleanChildNode() {
        for (const enemy of this.enemiesNode.children) {
            enemy.getComponent(EnemyTank).onEnemyDestroyed(true);
        }

        for (const bullet of this.playerBulletsNode.children) {
            bullet.getComponent(Bullet).onBulletDestory();
        }

        for (const bullet of this.enemyBulletsNode.children) {
            bullet.getComponent(Bullet).onBulletDestory();
        }

        for (const prop of this.propNode.children) {
            prop.getComponent(Prop).onPropDestroyed();
        }

        for (const block of this.blocksNode.children) {
            if (block.name != "camp") {
                block.destroy();
            }
        }
    }

    _loadMap() {
        let self = this;
        cc.assetManager.loadBundle("maps", (err: Error, bundle: cc.AssetManager.Bundle) => {
            bundle.load(this._game.level.toString(), cc.TextAsset, function (err: Error, file: cc.TextAsset) {
                let data = file.text;
                let index = 0;

                // 26*26布局
                for (let i = 0; i != 26; i++) {
                    for (let j = 0; j != 26; j++) {
                        let block: cc.Node;

                        switch (data[index++]) {
                            case '1':
                                block = cc.instantiate(self.blockForestPrefab);
                                block.name = "block_forest";
                                break;
                            case '2':
                                block = cc.instantiate(self.blockIcePrefab);
                                block.name = "block_ice";
                                break;
                            case '3':
                                block = cc.instantiate(self.blockWallPrefab);
                                block.name = "block_wall";
                                block.getComponent(BlockWall).init();
                                break;
                            case '4':
                                block = cc.instantiate(self.blockRiverPrefab);
                                block.name = "block_river";
                                block.getComponent(cc.Animation).play("river");
                                break;
                            case '5':
                                block = cc.instantiate(self.blockStonePrefab);
                                block.name = "block_stone";
                                block.getComponent(BlockStone).init();
                                break;
                            default:
                                break;
                        }
                    
                        // 从上往下、从左往右 每8个像素1个block
                        if (block) {
                            block.parent = self.blocksNode;
                            block.setAnchorPoint(0, 0);
                            block.setPosition(j * Globals.BLOCK_SIZE, (25 - i) * Globals.BLOCK_SIZE);
                        }
                    }
                }
            });
        });
    }

    _toNextStage() {
        this._game.level += 1;
        this._game.gameStart();
    }
}
